{{>licenseInfo}}
package {{invokerPackage}}

import org.json4s._
import sttp.client._
import sttp.model.StatusCode
import {{{apiPackage}}}.EnumsSerializers
import sttp.client.json4s.SttpJson4sApi
import sttp.client.monad.MonadError

class SttpSerializer(implicit val format: Formats = DefaultFormats ++ EnumsSerializers.all ++ Serializers.all,
                     implicit val serialization: org.json4s.Serialization = org.json4s.jackson.Serialization) extends SttpJson4sApi

class HttpException(val statusCode: StatusCode, val statusText: String, val message: String) extends Exception(s"[$statusCode] $statusText: $message")

object Helpers {

  // Helper to handle Optional header parameters
  implicit class optionalParams(val request: RequestT[Identity, Either[String, String], Nothing]) extends AnyVal {
    def header( header: String, optValue: Option[Any]): RequestT[Identity, Either[String, String], Nothing] = {
      optValue.map( value => request.header(header, value.toString)).getOrElse(request)
    }
  }

}

object ApiInvoker {

  /**
    * Allows request execution without calling apiInvoker.execute(request)
    * request.result can be used to get a monad wrapped content.
    *
    * @param request the apiRequest to be executed
    */
  implicit class ApiRequestImprovements[R[_], T](request: RequestT[Identity, Either[ResponseError[Exception], T], Nothing]) {

    def result(implicit backend: SttpBackend[R, Nothing, Nothing]): R[T] = {
      val responseT = request.send()
      val ME: MonadError[R] = backend.responseMonad
      ME.flatMap(responseT) {
        response =>
          response.body match {
            case Left(ex) => ME.error[T](new HttpException(response.code, response.statusText, ex.body))
            case Right(value) => ME.unit(value)
          }
      }
    }
  }

}
